
function tabgroup(id,parentNode,transx,transy,width,height,tabheight,cornerLeft,cornerRight,tabmargins,spaceBetweenTabs,tabStyles,activetabBGColor,tabwindowStyles,tabtextStyles,tabTitles,activeTabindex,hideContent,functionToCall) {
	var nrArguments = 19;
	var createTabgroup = true;
	if (arguments.length == nrArguments) {
		this.id = id;
		this.parentNode = parentNode; //can be of type string (id) or node reference (svg or g node)
		this.transx = transx;
		this.transy = transy;
		this.x = 0;
		this.y = 0;
		this.width = width;
		this.height = height;
		this.tabheight = tabheight;
		this.cornerLeft = cornerLeft; //values are "rect","round","triangle"
		this.cornerRight = cornerRight; //values are "rect","round","triangle"
		this.tabmargins = tabmargins;
		this.spaceBetweenTabs = spaceBetweenTabs;
		this.tabStyles = tabStyles;
		if (!this.tabStyles["fill"]) {
			this.tabStyles["fill"] = "lightgray";
		}
		this.activetabBGColor = activetabBGColor;
		this.tabwindowStyles = tabwindowStyles;
		this.tabtextStyles = tabtextStyles;
		if (!this.tabtextStyles["font-size"]) {
			this.tabtextStyles["font-size"] = 15;
		}
		this.tabTitles = tabTitles;
		if (this.tabTitles instanceof Array) {
			if (this.tabTitles.length == 0) {
				createTabgroup = false;
				alert("Error ("+this.id+"): the array 'tabTitles' has no elements!");
			}
		}
		else {
			createTabgroup = false;
			alert("Error ("+this.id+"): the array 'tabTitles' is not of type array!");
		}
		this.activeTabindex = activeTabindex;
		if (this.activeTabindex >= this.tabTitles.length) {
			createTabgroup = false;
			this.outOfBoundMessage(this.activeTabindex);
		}
		this.hideContent = hideContent; //boolean, defines whether the display of a tab should be set to "none","inherit"
		this.functionToCall = functionToCall;
		if (!(typeof(this.functionToCall) == "function" || typeof(this.functionToCall) == "object" || typeof(this.functionToCall) == "undefined")) {
			createTabgroup = false;
			alert("Error ("+this.id+"): functionToCall is of type '"+typeof(this.functionToCall)+"' and not of type 'function', 'object' or 'undefined'");
		}
	}
	else {
		createTabgroup = false;
		alert("Error ("+id+"): wrong nr of arguments! You have to pass over "+nrArguments+" parameters.");
	}
	if (createTabgroup) {
		this.parentGroup = null; //later a node reference to the parent group
		this.tabGroup = null; //later a reference to the group within the parentGroup
		this.tabwindows = new Array();
		this.timer = new Timer(this); //a Timer instance for calling the functionToCall
		this.timerMs = 200; //a constant of this object that is used in conjunction with the timer - functionToCall is called after 200 ms
		this.createTabGroup();
	}
	else {
		alert("Could not create tabgroup with id '"+this.id+"' due to errors in the constructor parameters");
	}
}

tabgroup.prototype.createTabGroup = function() {
	var result = this.testParent();
	if (result) {
	this.tabGroup = document.createElementNS(svgNS,"g");
	this.tabGroup.setAttributeNS(null,"transform","translate("+this.transx+","+this.transy+")");
	this.parentGroup.appendChild(this.tabGroup);
	//loop to create all tabs
	var currentX = this.x;
	for (var i=0;i<this.tabTitles.length;i++) {
		currentLeft = currentX;
		this.tabwindows[i] = new Array();
		//create group
		this.tabwindows[i]["group"] = document.createElementNS(svgNS,"g");
		this.tabGroup.appendChild(this.tabwindows[i]["group"]);
		//create tabTitle
		var tabtitles = this.tabTitles[i].split("\n");
		this.tabwindows[i]["tabTitle"] = document.createElementNS(svgNS,"text");
		this.tabwindows[i]["tabTitle"].setAttributeNS(null,"y",this.y + this.tabtextStyles["font-size"]);
		var value="";
		for (var attrib in this.tabtextStyles) {
			value = this.tabtextStyles[attrib];
			if (attrib == "font-size") {
				value += "px";
			}
			this.tabwindows[i]["tabTitle"].setAttributeNS(null,attrib,value);
		}
		this.tabwindows[i]["tabTitle"].setAttributeNS(null,"pointer-events","none");
		//create tspans and add text contents
		for (var j=0;j<tabtitles.length;j++) {
			var tspan = document.createElementNS(svgNS,"tspan");
			tspan.setAttributeNS(null,"x",currentX+this.tabmargins);
			var dy = this.tabtextStyles["font-size"]*1.1;
			if (j == 0) {
				dy = 0;
			}
			tspan.setAttributeNS(null,"dy",dy);
			var textNode = document.createTextNode(tabtitles[j]);
			tspan.appendChild(textNode);
			this.tabwindows[i]["tabTitle"].appendChild(tspan);
		}
		this.tabwindows[i]["group"].appendChild(this.tabwindows[i]["tabTitle"]);
		//get bbox
		var bbox = this.tabwindows[i]["tabTitle"].getBBox();
		currentX = Math.round(currentLeft + this.tabmargins * 2 + bbox.width);
		//check if text-anchor is middle and shift the x-values accordingly
		if (this.tabtextStyles["text-anchor"]) {
			if (this.tabtextStyles["text-anchor"] == "middle") {
				this.tabwindows[i]["tabTitle"].setAttributeNS(null,"transform","translate("+(bbox.width * 0.5)+" 0)");
			}
		}
		//now draw tabwindow background
		this.tabwindows[i]["tabbg"] = document.createElementNS(svgNS,"path");
		for (var attrib in this.tabwindowStyles) {
			this.tabwindows[i]["tabbg"].setAttributeNS(null,attrib,this.tabwindowStyles[attrib]);
		}
		//start the path for tab windows
		var d = "M";
		//left corner of tab
		if (this.cornerLeft == "rect") {
			d += currentLeft+" "+this.y;
		}
		if (this.cornerLeft == "triangle") {
			d += currentLeft+" "+(this.y+this.tabmargins)+"L"+(currentLeft+this.tabmargins)+" "+this.y;
		}
		if (this.cornerLeft == "round") {
			d += currentLeft+" "+(this.y+this.tabmargins)+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" -"+this.tabmargins;
		}
		//right corner of tab
		if (this.cornerRight == "rect") {
			d += "L"+currentX+" "+this.y;
		}
		if (this.cornerRight == "triangle") {
			d += "L"+(currentX-this.tabmargins)+" "+this.y+"L"+currentX+" "+(this.y+this.tabmargins);
		}
		if (this.cornerRight == "round") {
			d += "L"+(currentX-this.tabmargins)+" "+this.y+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" "+this.tabmargins;
		}
		d += "L"+currentX+" "+(this.y+this.tabheight);
		//complete the path for tab
		var dtab = d + "L"+currentLeft+" "+(this.y+this.tabheight)+"z";
		//complete the path for tab window
		d += "L"+(this.x+this.width)+" "+(this.y+this.tabheight)+"L"+(this.x+this.width)+" "+(this.y+this.height);
		d += "L"+this.x+" "+(this.y+this.height);
		if (currentLeft == this.x) {
			d += "z";
		}
		else {
			d += "L"+this.x+" "+(this.y+this.tabheight)+"L"+currentLeft+" "+(this.y+this.tabheight)+"z";
		}
		this.tabwindows[i]["tabbg"].setAttributeNS(null,"d",d);
		this.tabwindows[i]["group"].insertBefore(this.tabwindows[i]["tabbg"],this.tabwindows[i]["tabTitle"]);
		//create tab element
		this.tabwindows[i]["tab"] = document.createElementNS(svgNS,"path");
		for (var attrib in this.tabStyles) {
			this.tabwindows[i]["tab"].setAttributeNS(null,attrib,this.tabStyles[attrib]);
		}
		this.tabwindows[i]["tab"].setAttributeNS(null,"d",dtab);
		this.tabwindows[i]["tab"].setAttributeNS(null,"id",this.id+"__"+i);
		this.tabwindows[i]["tab"].addEventListener("click",this,false);
		this.tabwindows[i]["group"].insertBefore(this.tabwindows[i]["tab"],this.tabwindows[i]["tabTitle"]);
		//create group for tab content
		this.tabwindows[i]["content"] = document.createElementNS(svgNS,"g");
		this.tabwindows[i]["content"].setAttributeNS(null,"id",this.id+"__"+i+"_content");
		if (this.hideContent) {
			this.tabwindows[i]["content"].setAttributeNS(null,"display","none");
		}
		this.tabwindows[i]["group"].appendChild(this.tabwindows[i]["content"]);
		//set tab activate status
		this.tabwindows[i].activeStatus = true;
		//increment currentX with the space between tabs
		currentX += this.spaceBetweenTabs;
	}
	//activate one tab
	this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.activetabBGColor);
	this.tabGroup.appendChild(this.tabwindows[this.activeTabindex]["group"]);
	if (this.hideContent) {
		this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","inherit");
	}
	}
	else {
		alert("could not create or reference 'parentNode' of tabgroup with id '"+this.id+"'");
	}
 }
 
 //test if window group exists or create a new group at the end of the file
tabgroup.prototype.testParent = function() {
    //test if of type object
    var nodeValid = false;
    if (typeof(this.parentNode) == "object") {
    	if (this.parentNode.nodeName == "svg" || this.parentNode.nodeName == "g") {
    		this.parentGroup = this.parentNode;
    		nodeValid = true;
    	}
    }
    else if (typeof(this.parentNode) == "string") { 
    	//first test if Windows group exists
    	if (!document.getElementById(this.parentNode)) {
        	this.parentGroup = document.createElementNS(svgNS,"g");
        	this.parentGroup.setAttributeNS(null,"id",this.parentNode);
        	document.documentElement.appendChild(this.parentGroup);
        	nodeValid = true;
   		}
   		else {
       		this.parentGroup = document.getElementById(this.parentNode);
       		nodeValid = true;
   		}
   	}
   	return nodeValid;
}

tabgroup.prototype.handleEvent = function(evt) {
	var tab = evt.target;
	var id = tab.getAttributeNS(null,"id");
	var idArray = id.split("__");
	var index = parseInt(idArray[1]);
	this.activateTabByIndex(index,false);
	//firefunction
	this.timer.setTimeout("fireFunction",this.timerMs);
}

tabgroup.prototype.fireFunction = function() {
	if (typeof(this.functionToCall) == "function") {
		this.functionToCall(this.id,this.tabTitles[this.activeTabindex],this.activeTabindex);
	}
	if (typeof(this.functionToCall) == "object") {
		this.functionToCall.tabActivated(this.id,this.tabTitles[this.activeTabindex],this.activeTabindex);
	}
	if (typeof(this.functionToCall) == undefined) {
		return;
	}
}

tabgroup.prototype.activateTabByIndex = function(tabindex,fireFunction) {
	if (tabindex >= this.tabTitles.length) {
		this.outOfBoundMessage(tabindex);
		tabindex = 0;
	}
	//set old active tab to inactive
	this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.tabStyles["fill"]);
	if (this.hideContent) {
		this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","none");
	}
	//set new index
	this.activeTabindex = tabindex;
	//activate new tab
	this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.activetabBGColor);
	//reorder tabs
	this.tabGroup.appendChild(this.tabwindows[this.activeTabindex]["group"]);
	//set display
	if (this.hideContent) {
		this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","inherit");
	}
	if (fireFunction) {
		this.timer.setTimeout("fireFunction",this.timerMs);
	}
}

tabgroup.prototype.activateTabByTitle = function(title,fireFunction) {
	var tabindex = -1;
	for (var i=0;i<this.tabTitles.length;i++) {
		if (this.tabTitles[i] == title) {
			tabindex = i;
			break;
		}
	}
	if (tabindex != -1) {
		this.activateTabByIndex(tabindex,fireFunction);
	}
	else {
		alert("Error ("+this.id+"): Could not find title '"+title+"' in array tabTitles!");
	}
}

//add content to this.tabwindows[tabindex]["content"]
tabgroup.prototype.addContent = function(node,tabindex,inheritDisplay) {
	if (tabindex >= this.tabTitles.length) {
		this.outOfBoundMessage(tabindex);
	}
	else {
		if (typeof(node) == "string") {
			node = document.getElementById(node);
		}
		if (node != undefined || node != "null") {
			if (inheritDisplay) {
				node.setAttributeNS(null,"display","inherit");
			}
			this.tabwindows[tabindex]["content"].appendChild(node);
		}
	}
}

//remove content from this.tabwindows[tabindex]["content"]
tabgroup.prototype.removeContent = function(node,tabindex) {
	var deletedNode = undefined;
	if (tabindex >= this.tabTitles.length) {
		this.outOfBoundMessage(tabindex);
	}
	else {
		if (typeof(node) == "string") {
			node = document.getElementById(node);
		}
		if (node != undefined || node != "null") {
			deletedNode = this.tabwindows[tabindex]["content"].removeChild(node);
		}
	}
	return deletedNode;
}

//move the tab, reference is upper left corner
tabgroup.prototype.moveTo = function(x,y) {
	this.transx = x;
	this.transy = y;
	this.tabGroup.setAttributeNS(null,"transform","translate("+this.transx+","+this.transy+")");
}

//resize tabgroup
tabgroup.prototype.resize = function(width,height) {
	this.width = width;
	this.height = height;
	//loop to change all tab sizes
	var currentX = this.x;
	for (var i=0;i<this.tabTitles.length;i++) {
		currentLeft = currentX;
		//get bbox
		var bbox = this.tabwindows[i]["tabTitle"].getBBox();
		currentX = Math.round(currentLeft + this.tabmargins * 2 + bbox.width);
		//start the path for tab windows
		var d = "M";
		//left corner of tab
		if (this.cornerLeft == "rect") {
			d += currentLeft+" "+this.y;
		}
		if (this.cornerLeft == "triangle") {
			d += currentLeft+" "+(this.y+this.tabmargins)+"L"+(currentLeft+this.tabmargins)+" "+this.y;
		}
		if (this.cornerLeft == "round") {
			d += currentLeft+" "+(this.y+this.tabmargins)+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" -"+this.tabmargins;
		}
		//right corner of tab
		if (this.cornerRight == "rect") {
			d += "L"+currentX+" "+this.y;
		}
		if (this.cornerRight == "triangle") {
			d += "L"+(currentX-this.tabmargins)+" "+this.y+"L"+currentX+" "+(this.y+this.tabmargins);
		}
		if (this.cornerRight == "round") {
			d += "L"+(currentX-this.tabmargins)+" "+this.y+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" "+this.tabmargins;
		}
		d += "L"+currentX+" "+(this.y+this.tabheight);
		//complete the path for tab window
		d += "L"+(this.x+this.width)+" "+(this.y+this.tabheight)+"L"+(this.x+this.width)+" "+(this.y+this.height);
		d += "L"+this.x+" "+(this.y+this.height);
		if (currentLeft == this.x) {
			d += "z";
		}
		else {
			d += "L"+this.x+" "+(this.y+this.tabheight)+"L"+currentLeft+" "+(this.y+this.tabheight)+"z";
		}
		//set modified path elements
		this.tabwindows[i]["tabbg"].setAttributeNS(null,"d",d);
		//increment currentX with the space between tabs
		currentX += this.spaceBetweenTabs;
	}
}

//deactivate a single tab
tabgroup.prototype.disableSingleTab = function(tabindex) {
	if (tabindex >= this.tabTitles.length) {
		this.outOfBoundMessage(tabindex);
	}
	else {
		this.tabwindows[tabindex]["activeStatus"] = false;
		if (!this.tabwindows[tabindex]["tabClone"]) {
			this.tabwindows[tabindex]["tabClone"] = this.tabwindows[tabindex]["tab"].cloneNode(false);
			this.tabwindows[tabindex]["tabClone"].removeEventListener("click",this,false);
			this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"fill-opacity",0.5);
			if (this.tabwindows[tabindex]["tabClone"].hasAttributeNS(null,"cursor")){
				this.tabwindows[tabindex]["tabClone"].removeAttributeNS(null,"cursor");
			}
			this.tabwindows[tabindex]["group"].appendChild(this.tabwindows[tabindex]["tabClone"]);
		}
		else {
			this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"display","inherit");
			this.tabwindows[tabindex]["group"].appendChild(this.tabwindows[tabindex]["tabClone"]);
		}
	}
}

//deactivate all tabs
tabgroup.prototype.disableAllTabs = function() {
	for (var i=0;i<this.tabTitles.length;i++) {
		this.disableSingleTab(i);
	}
}

//deactivate all tabs
tabgroup.prototype.enableAllTabs = function() {
	for (var i=0;i<this.tabTitles.length;i++) {
		this.enableSingleTab(i);
	}
}

//activate a single tab
tabgroup.prototype.enableSingleTab = function(tabindex) {
	if (tabindex >= this.tabTitles.length) {
		this.outOfBoundMessage(tabindex);
	}
	else {
		this.tabwindows[tabindex]["activeStatus"] = true;
		if (this.tabwindows[tabindex]["tabClone"]) {
			this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"display","none");
		}
	}
}

//out of bound error message
tabgroup.prototype.outOfBoundMessage = function(tabindex) {
	alert("Error ("+this.id+"): the 'tabindex' (value: "+tabindex+") is out of bounds!\nThe index nr is bigger than the number of tabs.");
}
